#include "realpoly_snippet.h"
namespace RealPoly{

SparsePolyRing NewPolyRing(size_t myring); // forward declaration, not visible by end user


//! The following class is meant to set up a pool of all polynomial rings
class PolynomialRingPool{
	static PolynomialRing  getPolyRing(size_t id) {
			PolynomialRing ret = __rings.find(id)->second; 
			return ret; 
	}


	private:
		static map<size_t, PolynomialRing> __rings;
		friend class PolynomialRing;
		friend class Polynomial;
		friend pair< CoCoA::ring, vector<CoCoA::symbol> > CoCoA_Parser(size_t id);
};




map<size_t, PolynomialRing> PolynomialRingPool::__rings;


size_t PolynomialRing::__id_counter = 0;

//! the real ctor
PolynomialRing::PolynomialRing(const vector<string>& vars,  const Integer& ch) : __variables(vars), __characteristic(ch) { 
			__id = ++__id_counter;

			PolynomialRingPool::__rings.insert(std::make_pair(__id, *this)); // insert this new __id to the gloab ring pool
	}




Polynomial::Polynomial(const PolynomialRing& R, PolynomialType flag) : __flag(flag), __ring(R.__id) {
	switch(__flag) {
	case COCOA:
	      typedef RingElem T;
	      __data = new T(NewPolyRing(R.__id)); //
		 
	      break;
	}
}

Polynomial::~Polynomial(){
	switch(__flag) {
	case COCOA:
		{
	      typedef CoCoA::RingElem T;
		  delete (T*)__data; // buggy part
	      break;
		}
	default:
		throw NOT_IMPLEMENTED;
	}
}


pair< CoCoA::ring, vector<CoCoA::symbol> > CoCoA_Parser(size_t id) {
		PolynomialRing ri = PolynomialRingPool::getPolyRing(id);
		vector<CoCoA::symbol> syms;
		const vector<string>& vars=ri.__variables;
		for (size_t i=0; i< vars.size(); i++)
			syms.push_back(CoCoA::symbol(vars[i]));


		if (ri.__characteristic!=Integer(0))
			return make_pair(CoCoA::NewRingFp(integer2zz(ri.__characteristic)), syms);
		else
			return make_pair(CoCoA::RingQ(), syms);
	}

}




namespace RealPoly{
		
	CoCoA::ZZ  integer2zz(const Integer& c){
                        std::ostringstream oss (std::ostringstream::out);
                        oss << c;
                        std::istringstream iss(oss.str(),std::istringstream::in);
                        CoCoA::ZZ z;
                        iss >> z;
                        return z;
        }


	CoCoA::GlobalManager CoCoAinitialization; // initialize a CoCoA::GlobalManager


	class CoCoARingPool{

	friend SparsePolyRing NewPolyRing(size_t myring);

	private:
	static map<size_t, SparsePolyRing> __cocoa_rings;
	};


	map<size_t, SparsePolyRing> CoCoARingPool::__cocoa_rings; // initializing cocoa ring pool


	pair< CoCoA::ring, vector<CoCoA::symbol> > CoCoA_Parser(size_t);

	//! Create a CoCoA PolyRing from with ring id myring
	SparsePolyRing NewPolyRing(size_t myring){
			map<size_t, SparsePolyRing>::iterator pos=CoCoARingPool::__cocoa_rings.find(myring);
			if (pos != CoCoARingPool::__cocoa_rings.end()){
				SparsePolyRing R(pos->second);
				return R;
			}
			else{
				pair< CoCoA::ring, vector<CoCoA::symbol> > rp = CoCoA_Parser(myring);
				pair< map< size_t, SparsePolyRing >::iterator, bool > ret = 
				CoCoARingPool::__cocoa_rings.insert( std::make_pair(myring,CoCoA::NewPolyRing(rp.first,rp.second)));
				SparsePolyRing R(ret.first->second);
				return R; 
				}
			}
}

